﻿using Microsoft.ServiceBus.Messaging;
using Serilog;
using Sustainalytics.DataLayer;
using Sustainalytics.DataLayer.ConnectionStrings;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities;
using Sustainalytics.Entities.ConnectionStrings;
using Sustainalytics.Insights.Service;
using Sustainalytics.Replication.Publisher;
using System;
using System.Configuration;
using System.Diagnostics;

namespace Sustainalytics.Replication.Service
{
    class ServiceBusHandler
    {
        bool serviceRunning = false;
        
        IRepositoryCollection<News> newsRepository;
        IRepositoryCollection<Event> eventsRepository;
        IMostRecentActivityRepository mostRecentActivityRepository;
        IMostActiveReportRepository mostActiveReportRepository;
        IAccountsRepository accountsRepository;
        ICompanyScreeningRepository companyScreeningRepository;
        IFilterCriteriaRepository filterCriteriaRepository;
        IFiltersRepository filterRepository;
        IRepositoryCollection<UserFilterSettings> userFilterSettingsRepository;
        IRepositoryCollection<Portfolio> portfolioRepository;
        IRepositoryCollection<Portfolio> portfolioClientDwRepository;
        IRepositoryCollection<PortfolioDetails> portfolioDetailsRepository;
        IRepositoryCollection<PortfolioUserInput> portfolioUserInputRepository;
        ISubscribeToPortfolioRepository subscribeToPortfolioRepository;
        IInsightRepository insightRepository;

        /// <summary>
        /// Method called when service is started.
        /// </summary>
        public void Start()
        {
            serviceRunning = true;
            InitRepositories();
            ListenQueue();
        }
        
        /// <summary>
        /// Method called when service is stopped.
        /// </summary>
        public void Stop()
        {
            serviceRunning = false;
        }

        /// <summary>
        /// Initialize the repositories.
        /// </summary>
        private void InitRepositories()        
        {
            try
            {
                Trace.WriteLine($"Init repositories");
                string connStrClientPlatform = ConfigurationManager.ConnectionStrings["ClientPlatform"].ConnectionString;
                var connectionStringsManager = ConnectionStringsManager.GetInstance(
                    ConnectionStringsRepository.GetInstance(connStrClientPlatform));

                newsRepository = new RepositoryCollection<News>(connStrClientPlatform);
                eventsRepository = new RepositoryCollection<Event>(connStrClientPlatform);
                mostRecentActivityRepository = new MostRecentActivityRepository(connStrClientPlatform);
                mostActiveReportRepository = new MostActiveReportRepository(connStrClientPlatform);
                accountsRepository = AccountsRepository.GetAccountsRepository(connStrClientPlatform);
                companyScreeningRepository = CompanyScreeningRepository.GetCompanyScreeningRepository(connStrClientPlatform);
                filterCriteriaRepository = new FilterCriteriaRepository(connStrClientPlatform);
                filterRepository = new FiltersRepository(connStrClientPlatform);
                userFilterSettingsRepository = new RepositoryCollection<UserFilterSettings>(connStrClientPlatform);
                portfolioRepository = new RepositoryCollection<Portfolio>(connStrClientPlatform);
                portfolioClientDwRepository = new RepositoryCollection<Portfolio>(connectionStringsManager.GetConnectionString(ConnectionStringType.ClientDW));
                portfolioDetailsRepository = new RepositoryCollection<PortfolioDetails>(connStrClientPlatform);
                portfolioUserInputRepository = new RepositoryCollection<PortfolioUserInput>(connStrClientPlatform);
                subscribeToPortfolioRepository = new SubscribeToPortfolioRepository(connStrClientPlatform);
                insightRepository = new InsightRepository(connStrClientPlatform);
            }
            catch (Exception ex)
            {
                
                Log.Error(ex,"");
                Trace.WriteLine($"{ex.GetType().ToString()}, {ex.Message}, {ex.ToString()}");
            }
        }
        
        /// <summary>
        /// Subscribe to queue and process messages received
        /// </summary>
        public void ListenQueue()
        {
            SubscriptionClient client = null;
            try
            {
                string connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];
                string topicPath = ConfigurationManager.AppSettings["Microsoft.ServiceBus.TopicPath"];
                string regionEndpoint = ConfigurationManager.AppSettings["Microsoft.ServiceBus.RegionEndpoint"];

                client = SubscriptionClient.CreateFromConnectionString(connectionString, topicPath, regionEndpoint);
            }
            catch(Exception ex)
            {
                Log.Error(ex,"");
                Trace.WriteLine($"{ex.GetType().ToString()}, {ex.Message}, {ex.ToString()}");

            }

            // Configure the callback options.
            OnMessageOptions options = new OnMessageOptions();
            options.AutoComplete = false;
            options.AutoRenewTimeout = TimeSpan.FromMinutes(1);

            if (client != null)
            {
                client.OnMessage((message) =>
                {
                    try
                    {
                        ProcessMessage(message);
                        // Remove message from subscription.
                        message.Complete();
                    }
                    catch (Exception ex)
                    {
                        // Indicates a problem, unlock message in subscription.
                        message.Abandon();
                        Log.Error(ex,"");
                        Trace.WriteLine($"{ex.GetType().ToString()}, {ex.Message}, {ex.ToString()}");

                    }
                }, options);
            }
            else
            {
                Trace.WriteLine($"Client could not be initialized");
            }
        }

        void ProcessMessage(BrokeredMessage message)
        {

            ReplicationUtils.EntityType entityType = ReplicationUtils.MessageEntityType(message);
            ReplicationUtils.ConnectionStringType connectionStringType = ReplicationUtils.MessageConnectionStringType(message);

            switch (entityType)
            {
                case ReplicationUtils.EntityType.News:
                    MessageHandler.ProcessMessage<News>(message, newsRepository);
                    break;
                case ReplicationUtils.EntityType.Event:
                    MessageHandler.ProcessMessage<Event>(message, eventsRepository);
                    break;
                case ReplicationUtils.EntityType.MostRecentActivity:
                    MessageHandler.ProcessMostRecentActivityMessage(message, mostRecentActivityRepository);
                    break;
                case ReplicationUtils.EntityType.MostActiveReport:
                    MessageHandler.ProcessMostActiveReportMessage(message, mostActiveReportRepository);
                    break;
                case ReplicationUtils.EntityType.AuthCredentials:
                    MessageHandler.ProcessAuthMessage(message, accountsRepository);
                    break;
                case ReplicationUtils.EntityType.Filter:
                    MessageHandler.ProcessFilterMessage(message, filterRepository);
                    break;
                case ReplicationUtils.EntityType.FilterCriteria:
                    MessageHandler.ProcessFilterCriteriaMessage(message, filterCriteriaRepository, companyScreeningRepository);
                    break;
                case ReplicationUtils.EntityType.UserFilterSettings:
                    MessageHandler.ProcessMessage<UserFilterSettings>(message, userFilterSettingsRepository);
                    break;
                case ReplicationUtils.EntityType.Portfolio:                    
                    if (connectionStringType == ReplicationUtils.ConnectionStringType.ClientPlatform)
                        MessageHandler.ProcessMessage<Portfolio>(message, portfolioRepository);
                    else if (connectionStringType == ReplicationUtils.ConnectionStringType.ClientDW)
                        MessageHandler.ProcessMessage<Portfolio>(message, portfolioClientDwRepository);
                    break;
                case ReplicationUtils.EntityType.PortfolioDetails:
                    MessageHandler.ProcesssPortfolioDetailsMessage(message, portfolioDetailsRepository);
                    break;
                case ReplicationUtils.EntityType.PortfolioUserInput:
                    MessageHandler.ProcesssPortfolioUserInputMessage(message, portfolioUserInputRepository);
                    break;
                case ReplicationUtils.EntityType.SubscribeToPortfolio:
                    MessageHandler.ProcesssSubscribeToPortfolioMessage(message, subscribeToPortfolioRepository);
                    break;
                case ReplicationUtils.EntityType.Insight:
                    MessageHandler.ProcessInsightMessage(message, insightRepository);
                    break;
                    

            }
        }
    }
}
